package com.example.demo.poc.executor;

import com.example.demo.poc.domain.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

//@Service
@Slf4j
public class StrategyExecutor {

    private CIMObjectConfig cimObjectConfig;
    private ContextProcessor ctxProc;
    private FormulaProcessor frmProc;
    private Map<String,Map<String,Object>> datasetMappingStore;

    public StrategyExecutor(CIMObjectConfig cimObjectConfig, ContextProcessor ctxProc, FormulaProcessor frmProc) {
        this.cimObjectConfig = cimObjectConfig;
        this.ctxProc = ctxProc;
        this.frmProc = frmProc;
        this.datasetMappingStore = new ConcurrentHashMap<>();
    }

    public CIMObjectPlainValue changeCIMObjectConfigtoValue() {

        CIMObjectPlainValue cimObjectPlainValue = new CIMObjectPlainValue();
        List<DataSetConfig> dataSetConfigList = this.cimObjectConfig.getDatasetsConfig();
        List<CIMObjectDataSetKVStore> dvsList = new ArrayList<>();
        for (DataSetConfig dsc : dataSetConfigList) {
            CIMObjectDataSetKVStore cimDvs = changeCIMObjectDataSetConfigtoValue(dsc);
            dvsList.add(cimDvs);
            this.datasetMappingStore.put(cimDvs.getDataSetName(), cimDvs.getProperties());
        }
        cimObjectPlainValue.setDatasets(dvsList);
        cimObjectPlainValue.setCimObjectId(this.datasetMappingStore.get(CIMObjectPlainValue.DEFAULIT_DATASET_NAME).get(CIMObjectPlainValue.CIM_OBJECT_ID_K).toString());
        cimObjectPlainValue.setCimObjectType(this.datasetMappingStore.get(CIMObjectPlainValue.DEFAULIT_DATASET_NAME).get(CIMObjectPlainValue.CIM_TYPE_NAME_K).toString());
        this.datasetMappingStore.get(CIMObjectPlainValue.DEFAULIT_DATASET_NAME).remove(CIMObjectPlainValue.CIM_TYPE_NAME_K);

        return cimObjectPlainValue;
    }


    public CIMObjectDataSetKVStore changeCIMObjectDataSetConfigtoValue(DataSetConfig dataSetConfig) {

        DataSetConfig dsc = dataSetConfig;
        CIMObjectDataSetKVStore dvs = new CIMObjectDataSetKVStore();
        Map<String, Object> dataSetProps = new ConcurrentHashMap<>();
        for (ConfigPropItem cpi : dsc.getProps()) {
            Map<String, Object> props = parseValueMap(cpi);
            dataSetProps.putAll(props);
        }
        dvs.setProperties(dataSetProps);
        dvs.setDataSetName(dataSetProps.get(DataSetConfig.DS_NAME).toString());
        dataSetProps.remove(DataSetConfig.DS_NAME);
        return dvs;
    }

    public Map<String, Object> parseValueMap(ConfigPropItem cpi) {
        String propName = cpi.getPropertyName();
        String formula = cpi.getFormula();
        String pValue = cpi.getValue();
        String type = cpi.getType();
        List<ConfigSourceItem> csiList = cpi.getFrom();
        Map<String, Object> resultMap = new ConcurrentHashMap<>();


        List<Map<String, Object>> _cxtList = new ArrayList<>();
        Map<String, Object> _cxtMap = new ConcurrentHashMap<>();

        for (ConfigSourceItem csi : csiList) {

            String vName = csi.getVariableName();
            String jpValue = csi.getValue();


            List<Object> valueList = this.ctxProc.getPathValueList(jpValue);
            if (valueList == null) {
                continue;
            } else {
                if (vName.indexOf(':') > 0) {
                    String[] nameArr = vName.split(":");

                    for (Object o : valueList) {
                        if (o instanceof LinkedHashMap) {
                            Map map = parseKVPair(nameArr, (LinkedHashMap<String, Object>) o);
                            _cxtList.add(map);
                        }
                    }

                } else if (!StringUtils.isBlank(cpi.getFormula())) {
                    if (valueList != null & valueList.size() > 0) {

                        if (valueList.size() == 1) {
                            this.frmProc.put(vName, valueList.get(0));
                        } else {
                            this.frmProc.put(vName, valueList);
                        }
                    }
                }
            }
        }

        if (StringUtils.isBlank(formula)) {

            if (!StringUtils.isBlank(pValue) && !pValue.contains("${")) {
                resultMap.put(propName,cpi.getValue());
            } else {

                for (Map<String, Object> map : _cxtList) {
                    if (!CollectionUtils.isEmpty(map)) {
                        if (propName.startsWith("${")) {
                            String k = WildCardUtils.getBraceInnerLongestString(propName).get(0);
                            String _propKey = map.get(k).toString();
                            if (cpi.getValue().startsWith("${")) {
                                k = WildCardUtils.getBraceInnerLongestString(pValue).get(0);
                                Object _propValue = map.get(k);
                                resultMap.put(_propKey, _propValue);
                            }
                        }
                    }
                }
            }
        } else {
            Object o = this.frmProc.exec(formula);
            resultMap.put(propName, o);
        }
        return resultMap;

    }


    private Map<String, Object> parseKVPair(String[] key, LinkedHashMap<String, Object> valueMap) {

        Map<String, Object> rMap = new ConcurrentHashMap<>();
        for (int i = 0; i < key.length; i++) {
            String k = key[i];
            if (valueMap.containsKey(k)) {
                rMap.put(k, valueMap.get(k));
            } else {
                log.error("JsonPath value is a map , but not contains key with '" + key + "'.");
                return null;
            }
        }

        return rMap;
    }


//    public static void main(String[] args) {
//        String a ="a:b:c:d";
//        System.out.println(a.split(":")[2]);
//    }

}
